
static void __hrtimer_reprogram(struct hrtimer_cpu_base *cpu_base,
                                struct hrtimer *next_timer,
                                ktime_t expires_next)
{
    cpu_base->expires_next = expires_next;

    /*
     * If hres is not active, hardware does not have to be
     * reprogrammed yet.
     *
     * If a hang was detected in the last timer interrupt then we
     * leave the hang delay active in the hardware. We want the
     * system to make progress. That also prevents the following
     * scenario:
     * T1 expires 50ms from now
     * T2 expires 5s from now
     *
     * T1 is removed, so this code is called and would reprogram
     * the hardware to 5s from now. Any hrtimer_start after that
     * will not reprogram the hardware due to hang_detected being
     * set. So we'd effectively block all timers until the T2 event
     * fires.
     */
    if (!hrtimer_hres_active(cpu_base) || cpu_base->hang_detected)
        return;

    tick_program_event(expires_next, 1);
}

/*
 * When a timer is enqueued and expires earlier than the already enqueued
 * timers, we have to check, whether it expires earlier than the timer for
 * which the clock event device was armed.
 *
 * Called with interrupts disabled and base->cpu_base.lock held
 */
static void hrtimer_reprogram(struct hrtimer *timer, bool reprogram)
{
    struct hrtimer_cpu_base *cpu_base = this_cpu_ptr(&hrtimer_bases);
    struct hrtimer_clock_base *base = timer->base;
    ktime_t expires = ktime_sub(hrtimer_get_expires(timer), base->offset);

    /*
     * CLOCK_REALTIME timer might be requested with an absolute
     * expiry time which is less than base->offset. Set it to 0.
     */
    if (expires < 0)
        expires = 0;

    if (timer->is_soft)
    {
        /*
         * soft hrtimer could be started on a remote CPU. In this
         * case softirq_expires_next needs to be updated on the
         * remote CPU. The soft hrtimer will not expire before the
         * first hard hrtimer on the remote CPU -
         * hrtimer_check_target() prevents this case.
         */
        struct hrtimer_cpu_base *timer_cpu_base = base->cpu_base;

        if (timer_cpu_base->softirq_activated)
            return;

        if (!ktime_before(expires, timer_cpu_base->softirq_expires_next))
            return;

        timer_cpu_base->softirq_next_timer = timer;
        timer_cpu_base->softirq_expires_next = expires;

        if (!ktime_before(expires, timer_cpu_base->expires_next) ||
            !reprogram)
            return;
    }

    /*
     * If the timer is not on the current cpu, we cannot reprogram
     * the other cpus clock event device.
     */
    if (base->cpu_base != cpu_base)
        return;

    if (expires >= cpu_base->expires_next)
        return;

    /*
     * If the hrtimer interrupt is running, then it will reevaluate the
     * clock bases and reprogram the clock event device.
     */
    if (cpu_base->in_hrtirq)
        return;

    cpu_base->next_timer = timer;

    __hrtimer_reprogram(cpu_base, timer, expires);
}

/*
 * Reprogram the event source with checking both queues for the
 * next event
 * Called with interrupts disabled and base->lock held
 */
static void hrtimer_force_reprogram(struct hrtimer_cpu_base *cpu_base, int skip_equal)
{
    ktime_t expires_next;

    expires_next = hrtimer_update_next_event(cpu_base);

    if (skip_equal && expires_next == cpu_base->expires_next)
        return;

    __hrtimer_reprogram(cpu_base, cpu_base->next_timer, expires_next);
}
